//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <bsp.h>

#include "asciikey.h"
#include "vkey.h"

typedef struct KBDStatus
{
    uint8_t     uScanCode;
    uint8_t     uVirKey;
    uint16_t    uFlags;          //Event type, one of up/down/special
    bool_t      bKeyPress;       // TRUE: Press; FALSE: Release
    uint16_t    uLedStatus;
    uint16_t    uKbdStatus;
    uint8_t     uKeyboardIdentifier;
} KBDStatus;

static uint8_t uNumSymbols[] = {
    0x29, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28
};

static uint8_t uGenericSymbols0[] = {
    0x3B, 0x3D, 0x2C, 0x2D, 0x2E, 0x2F
};

static uint8_t uGenericSymbols1[] = {
    0x3A, 0x2B, 0x3C, 0x5F, 0x3E, 0x3F
};

static uint8_t uGenericSymbols2[] = {
    0x5B, 0x5C, 0x5D, 0x27
};

static uint8_t uGenericSymbols3[] = {
    0x7B, 0x7C, 0x7D, 0x22
};

//Translate keyboard data to Ascii
int TranslateVirtualcodeToASCII(uint8_t uVirtualcode, uint16_t uLedState,
    uint16_t uKeyboardState)
{
    if (VK_SPACE == uVirtualcode) {//SPACE
        return ASCII_SPACE;
    }

    //Letter key is pressed
    if (uVirtualcode >= VK_A && uVirtualcode <= VK_Z) {
        //Ctrl + (A-Z). Only Ctrl is pressed, while Shift
        // and ALT are not pressed.
        if ((uKeyboardState & KBD_CAS) == KBD_CTRL) {
            return (uVirtualcode + 1 - VK_A);
        }

        //capital letter
        if (((uLedState & KBD_CAPLOCK) == KBD_CAPLOCK) ^
            ((uKeyboardState & KBD_CAS) == KBD_SHIFT)) {
            return uVirtualcode;
        }

        //small letter
        return (uVirtualcode + 0x20);
    }

    //VK_0 - VK_9 key is pressed
    if (uVirtualcode >= VK_0 && uVirtualcode <= VK_9) {
        //Only SHIFT and a number key are pressed
        if ((uKeyboardState & KBD_CAS) == KBD_SHIFT) { // symbols
            return uNumSymbols[uVirtualcode - VK_0];
        }
        //Ctrl, Shift and a number key are pressed while ALT is not
        // pressed.(vi)
        else if ((uKeyboardState & KBD_CAS) == (KBD_SHIFT | KBD_CTRL)) {
            switch (uVirtualcode) {
                case VK_2://CTRL + @
                    return ASCII_At;
                case VK_6://CTRL + ^
                    return 0x1E;
                default:
                    return 0;
            }
        }
        //Only Ctrl and a number key are pressed
        else if((uKeyboardState & KBD_CAS) == KBD_CTRL) {
        	switch (uVirtualcode) {
                case VK_2://CTRL + @
                    return ASCII_At;
                default:
                    return 0;
            }
        }
        else if (!uKeyboardState) { // Number
            return uVirtualcode;
        }
        else
            return 0;
    }

    //Ctrl + \,|, [,{, ],}, _,-.
    //Alt is not pressed, Ctrl is pressed.
    if ((uKeyboardState & KBD_CTRL) && (!(uKeyboardState & KBD_ALT))) {
        switch (uVirtualcode) {
            case VK_HYPHEN://Ctrl + -
                return 0x1F;
            case VK_LBRACKET://Ctrl + [
                return 0x1B;
            case VK_BACKSLASH://Ctrl + \, |
                return 0x1C;
            case VK_RBRACKET://Ctrl + ]
                return 0x1D;
            default:
                break;
        }
    }

    //Symbols:  ; = , - . /
    if (uVirtualcode >= VK_SEMICOLON && uVirtualcode <= VK_SLASH) {
        if (uKeyboardState & KBD_SHIFT) {
            return uGenericSymbols1[uVirtualcode - VK_SEMICOLON];
        }
        else {
            return uGenericSymbols0[uVirtualcode - VK_SEMICOLON];
        }
    }

    //Symbols:  ` ~
    if (VK_BACKQUOTE == uVirtualcode) {
        if (uKeyboardState & KBD_SHIFT) {
            return 0x7E;
        }
        else {
            return 0x60;
        }
    }

    //Symbols:  [ \ ] '
    if (uVirtualcode >= VK_LBRACKET && uVirtualcode <= VK_APOSTROPHE) {
        if (uKeyboardState & KBD_SHIFT) {
            return uGenericSymbols3[uVirtualcode - VK_LBRACKET];
        }
        else {
            return uGenericSymbols2[uVirtualcode - VK_LBRACKET];
        }
    }

    //Before this line, keyboard state affect the pressed key.
    //After this line, Only the a key pressed without ctrl, alt and shift
    if (uKeyboardState) {
        return 0;
    }

    //only a key in little keyboard is pressed
    if (uVirtualcode >= VK_NUMPAD0 && uVirtualcode <= VK_NUMPAD9) {
        return (uVirtualcode - 0x30);
    }

    //Little Keyboard Symbols
    if ((uVirtualcode >= VK_MULTIPLY) && (uVirtualcode <= VK_DIVIDE)) {
        if (uVirtualcode == VK_SEPARATOR)
            return ASCII_ENTER;
        else
            return (uVirtualcode - 0x40);
    }

    //F1~F10: return 0xBB~0xC4
    if ((uVirtualcode >= VK_F1) && (uVirtualcode <= VK_F10)) {
        return (uVirtualcode - VK_F1 + 0xBB);
    }

    //F11, F12: return 0xD7,0xD8
    if ((uVirtualcode >= VK_F11) && (uVirtualcode <= VK_F12)) {
        return (uVirtualcode - VK_F11 + 0xD7);
    }

    switch (uVirtualcode) {
        case VK_RETURN: // Enter
            return ASCII_ENTER;
        case VK_TAB:
            return ASCII_Tab;
        case VK_ESCAPE:
            return KEY_ESC;
        case VK_LEFT:
            return ASCII_LeftArrow;
        case VK_RIGHT:
            return ASCII_RightArrow;
        case VK_INSERT:
            return ASCII_Insert;
        case VK_BACK:
            return ASCII_BackSpace;
        case VK_DELETE:
            return ASCII_Delete;
        case VK_HOME:
            return ASCII_Home;
        case VK_END:
            return ASCII_End;
        case VK_UP:
            return ASCII_UpArrow;
        case VK_DOWN:
            return ASCII_DownArrow;
        case VK_PRIOR:
            return ASCII_PageUp;
        case VK_NEXT:
            return ASCII_PageDown;
        default:
            return 0;
    }
}
